/* 
 * PageUtils.java      1.00    2008-02-15 
 *
 * Copyright (c) 2010 frida. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information
 * of frida.  You shall not disclose such Confidential Information
 * and shall use it only in accordance with the terms of the license agreement
 * you entered into with frida.
 */
package doit.framework.util;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

/**
 * <pre>
 * system      : 공통
 * menu        : 공통
 * source      : PageUtils.java
 * description : 페이징 유틸
 * </pre> 
 * @version
 * <pre> 
 * 1.0	2008-02-15  frida
 * 1.1	
 * </pre>
 */

@SuppressWarnings("unchecked")

public class PageUtils {
	public static final String[] ROWS_PER_PAGE_VALUES = {"10", "20", "50", "100"};
	public static final String[] PAGES_PER_INDEX_VALUES = {"5", "10", "15", "20", "25", "30"};
	
	public static final String PAGE_DELIMITER_DEFAULT = "  ";
	public static final String PAGE_UNIT_EXP = " 페이지";
	public static final String ROWS_UNIT_EXP = " 건";
	
	public static final int PAGE_INPUT_CHAR_WIDTH = 8;
	
	public static final int ROWS_PER_PAGE_DEFAULT = 10;
	public static final int PAGES_PER_INDEX_DEFAULT = 10;
	
//	public static final String SELECTOR_CLASS = "htc";
	public static final String SELECTOR_CLASS = "combo";
	
	public static final String PGI_PAGE = "page";
	public static final String PGI_ORDER_BY = "orderBy";
	public static final String PGI_ROWS_PER_PAGE = "rowsPerPage";
	public static final String PGI_PAGES_PER_INDEX = "pagesPerIndex";
	public static final String PGI_LOCATION = Constants.VL_LOCATION;
	public static final String PGI_METHOD = "method";

	private PageUtils() {
		super();
	}
	
	/**
	 * 인덱스 위치값을 통해 인덱스의 첫 페이지 위치를 리턴하는 함수이다.
	 * @return long 주어진 인덱스 위치값에 대한 첫 페이지 위치값
	 * @param index long 인덱스 위치값
	 * @param pagesPerIndex int 한 인덱스를 구성하기 위한 페이지 수 
	 */
	public static long getFirstPageOfIndex(
		long index,
		int pagesPerIndex) {
		return (index - 1) * pagesPerIndex + 1;
	}
	/**
	 * 페이지 위치값을 통해 페이지의 첫 Row 위치를 리턴하는 함수이다.
	 * @return long 주어진 페이지 위치값에 대한 첫 Row 위치값
	 * @param page long 페이지 위치값
	 * @param rowsPerPage int 한 페이지를 구성하기 위한 Row 수
	 */
	public static long getFirstRowOfPage( long page, int rowsPerPage) {
		return (page - 1) * rowsPerPage + 1;
	}
	/**
	 * 페이지 위치값을 통해 페이지가 속한 인덱스 위치값을 리턴하는 함수이다.
	 * @return long 인덱스 위치값
	 * @param pages int 페이지 위치값
	 * @param pagesPerIndex int 한 인덱스를 구성하기 위한 페이지 수
	 */
	public static long getIndexOfPage( long pages, int pagesPerIndex) {
		return (long) Math.ceil((float) pages / pagesPerIndex);
	}
	/**
	 * Row 위치값을 통해 Row가 속한 페이지 위치값을 리턴하는 함수이다.
	 * @return int 페이지 위치값
	 * @param rows int Row 위치값
	 * @param rowsPerPage int 한 페이지를 구성하기 위한 Row 수
	 */
	public static long getPageOfRow( long rows, int rowsPerPage) {
		 return (long) Math.ceil((float) rows / rowsPerPage);
	}

    /**
     * 타겟 인덱스로 해당 인덱스에 대한  타겟 페이지를 가져온다.
     * 
     * @param targetIndex 타겟 인덱스.
     * @return 타겟 인덱스에 대한 타겟 페이지.
     */
    private static long getTargetPage( long targetIndex, int pagesPerIndex) {
        return getFirstPageOfIndex(
                    targetIndex,
                    pagesPerIndex );
    }
    
    /**
     * 페이징을 위한 링크(A) 태그를 만들어 준다.
     * 
     * @param targetRow 페이징할 로우.
     * @param titleAttr A 태그의 TITLE 속성에 넣을 값.
     * @param whichImage A 태그 사이에 넣을 이미지.
     * @param defaultImage 설정 파일에 이미지 경로 값이 없는 경우 사용할 이미지.
     * @return 페이징을 위한 링크 태그 문자열.
     */
    private static String getPagingTag( HttpServletRequest request, long targetPage, String titleAttr, String whichImage, String defaultImage ) {
        return
            new StringBuffer( "<a href=\"javascript:showPage('" )
                .append( targetPage )
                .append( "')\" title=\"" )
                .append( titleAttr )
                .append( "\">" )
                .append( getImageTag( request, whichImage, titleAttr, defaultImage ) )
                .append( "</a>" )
                .toString();
    }
	
	public static String generateScript(String location, String method) {
		StringBuffer sb = new StringBuffer();
		
//		sb.append("<!-- Paging Script Start -->").append("\n");
		
		sb.append("<SCRIPT language=\"JavaScript\">").append("\n");
		sb.append("function showPage( page) {").append("\n");
		sb.append("   var frm = $(\"" + PGI_PAGE + "\").form;").append("\n");  
		sb.append("   $(\"" + PGI_PAGE + "\").value = page;").append("\n");
		sb.append("   $(\"method\").value = \"" + method + "\";").append("\n");
		sb.append("   frm.action=\"" + location + "\";").append("\n");
		sb.append("   frm.submit();").append("\n");
		sb.append("}").append("\n");
		sb.append("function showOrderByPage(page, order) {").append("\n");
		sb.append("   var frm = $(\"" + PGI_PAGE + "\").form;").append("\n");
		sb.append("   $(\"" + PGI_PAGE + "\").value = page;").append("\n");
		sb.append("   $(\"" + PGI_ORDER_BY + "\").value = order;").append("\n");
		sb.append("   $(\"method\").value = \"" + method + "\";").append("\n");
		sb.append("   frm.action=\"" + location + "\";").append("\n");
		sb.append("   frm.submit();").append("\n");
		sb.append("}").append("\n");
		sb.append("function showPageByEnter( page) {").append("\n");
		sb.append("   if( Event.element(event) == $(\"" + PGI_PAGE + "\") && event.keyCode == 13) {").append("\n");
		sb.append("       alert( page);").append("\n");
		sb.append("       if( isFinite( page)) {").append("\n");
		sb.append("           showPage( page);").append("\n");
		sb.append("       }").append("\n");
		sb.append("       else {").append("\n");
		sb.append("           alert(\"이동하고자 하는 "+ PAGE_UNIT_EXP + " 번호를 입력하십시오.\");").append("\n");
		sb.append("       }").append("\n");
		sb.append("   }").append("\n");
		sb.append("}").append("\n");
		sb.append("function changeRows( rows) {").append("\n");
		sb.append("   var frm = $(\"" + PGI_PAGE + "\").form;").append("\n");
		sb.append("   $(\"" + PGI_ROWS_PER_PAGE + "\").value = rows;").append("\n");
		sb.append("   $(\"page\").value = 1;").append("\n");
		sb.append("   $(\"method\").value = \"" + method + "\";").append("\n");
		sb.append("   frm.action=\"" + location + "\";").append("\n");
		sb.append("   frm.submit();").append("\n");
		sb.append("}").append("\n");
		sb.append("function changePages( pages) {").append("\n");
		sb.append("   var frm = $(\"" + PGI_PAGE + "\").form;").append("\n");
		sb.append("   $(\"" + PGI_PAGES_PER_INDEX + "\").value = pages;").append("\n");
		sb.append("   $(\"method\").value = \"" + method + "\";").append("\n");
		sb.append("   frm.action=\"" + location + "\";").append("\n");
		sb.append("   frm.submit();").append("\n");
		sb.append("}").append("\n");
		sb.append("</SCRIPT>").append("\n");
		
//		sb.append("<!-- Paging Script End -->").append("\n");
		
		return sb.toString();
	}
	
	public static String generateInput( long page, String orderBy , long rowsPerPage, long pagesPerIndex) {
		StringBuffer sb = new StringBuffer();
		
		sb.append("<!-- Paging Hidden Parameters Start -->").append("\n");
		
		sb.append("<INPUT name=\"" + PGI_PAGE + "\" id=\"" + PGI_PAGE + "\" type=\"hidden\" value=\"" + page + "\">").append("\n");
		sb.append("<INPUT name=\"" + PGI_ORDER_BY + "\" id=\"" + PGI_ORDER_BY + "\" type=\"hidden\" value=\"" + orderBy + "\">").append("\n");
		sb.append("<INPUT name=\"" + PGI_ROWS_PER_PAGE + "\" id=\"" + PGI_ROWS_PER_PAGE + "\" type=\"hidden\" value=\"" + rowsPerPage + "\">").append("\n");
		sb.append("<INPUT name=\"" + PGI_PAGES_PER_INDEX + "\" id=\"" + PGI_PAGES_PER_INDEX + "\" type=\"hidden\" value=\"" + pagesPerIndex + "\">").append("\n");
		
		sb.append("<!-- Paging Hidden Parameters End -->").append("\n");
		
		return sb.toString();
	}
	
    /**
     * 이동할 페이지를 선택할 수 있는 select 구성.
     * 
     * @param page 현재페이지.
     * @param pages 페이지수.
     * @param pagesPerIndex index 당 페이지 설정값.
     * @return 인덱스 이동을 위한 링크 문자열.
     */
	public static String generatePageIndexes( HttpServletRequest request, long page, long pages, int pagesPerIndex) {

        long index = getIndexOfPage( page, pagesPerIndex);
        
        long startPage = 0;
        long endPage = 0;
        long indexes = 0;
        
        StringBuffer retStr = new StringBuffer();
        if (pages < 1) {
        	return retStr.toString();
        }
        
        if( page > 0) {
			startPage =	getFirstPageOfIndex( index, pagesPerIndex);
			endPage = getFirstPageOfIndex( index + 1, pagesPerIndex);
			indexes = getIndexOfPage( pages, pagesPerIndex);
        }
        
		retStr.append("<div id=\"page_index\" class=\"pagination\">").append("\n");
		
//		retStr.append( showMoveFirstPage( page)).append("\n");
		retStr.append( showMoveBeforeIndex( request, index, pagesPerIndex)).append("\n");
//		retStr.append( showMoveBeforePage( page)).append("\n");
		
//		retStr.append("			<ol>\n");
		
		int count = 0;
		
		if ( startPage > 10  ) {
			for ( long targetPage = 1 ; 3 > targetPage; targetPage++) {
				retStr.append("<a href='javascript:showPage(" + targetPage + ")' onfocus=\"this.blur()\">" + targetPage + "</a>");
			}
			retStr.append("...");
		}
		
		for ( long targetPage = startPage; targetPage < endPage; targetPage++) {
			if (targetPage <= pages) {

				if( page == targetPage )	{
					retStr.append("<span class=\"current\">" + targetPage + "</span>");
				}
				else {
					retStr.append("<a href='javascript:showPage(" + targetPage + ")' onfocus=\"this.blur()\">" + targetPage + "</a>");
				}
				count++;
			}
		}
		
		if ( endPage < pages - 1  ) {
			retStr.append("...");
			for ( long targetPage = pages -1 ; targetPage <= pages; targetPage++) {
				retStr.append("<a href='javascript:showPage(" + targetPage + ")' onfocus=\"this.blur()\">" + targetPage + "</a>");
			}
		}
		retStr.append("\n");
//		if( count == 0)
//			retStr.append("			<li class=\"first\">&nbsp;</li>").append("\n");
		
//		retStr.append("			</ol>\n");
		
//		retStr.append( showMoveNextPage( page, pages)).append("\n");
		retStr.append( showMoveNextIndex( request, index, pagesPerIndex, indexes)).append("\n");
//		retStr.append( showMoveEndPage(page, pages)).append("\n");

		retStr.append("</div>").append("\n");
		
		return retStr.toString();
	}
	
    /**
     * 이동할 페이지를 선택할 수 있는 select 구성.
     * 
     * @param page 현재페이지.
     * @param pages 페이지수.
     * @return select tag 문자열.
     */
	public static String generateExpTotalRows( long rows) {
        StringBuffer rtnStr = new StringBuffer( "<span class=\"total_rows\">" );
        
        rtnStr.append( "전체 " ).append( rows).append( ROWS_UNIT_EXP);

        return rtnStr.append( "</span>" ).toString();
	}
	
    /**
     * 이동할 페이지를 선택할 수 있는 select 구성.
     * 
     * @param page 현재페이지.
     * @param pages 페이지수.
     * @return select tag 문자열.
     */
	public static String generatePageSelector( long page, long pages) {
        StringBuffer rtnStr = new StringBuffer( "<div class=\"page_select\">" );
        
        rtnStr.append( "<select class=\"" + SELECTOR_CLASS + "\" OnChange=\"showPage(this.value)\">" );
        for ( long targetPage = 1; targetPage <= pages; targetPage++ ) {
            rtnStr
                .append( "<option value=\"" )
                .append( targetPage )
                .append( "\"" );
            if ( targetPage == page ) {
                rtnStr.append( " selected" );
            }
            rtnStr.append( ">").append( targetPage ).append( "</option>" );
        }
        rtnStr.append( "</select>" );            

        return rtnStr.append( "</div>" ).toString();
	}
	
	public static String generatePageTextInput( long page, long pages) {
        StringBuffer rtnStr = new StringBuffer( "<span class=\"page_text_text\">" );

		rtnStr.append("<INPUT type=\"text\" class=\"txt w74\" value=\"").append(page)
				.append( "\" style=\"text-align: right;\" onKeyDown=\"showPageByEnter(this.value)\">").append("\n");
        rtnStr.append(" / ").append( pages).append( PAGE_UNIT_EXP).append("\n");

        return rtnStr.append( "</span>" ).toString();
	}

	public static String generatePageTextInput( HttpServletRequest request, long page, long pages, int pagesPerIndex) {
        StringBuffer rtnStr = new StringBuffer( "<span class=\"page_text_input\">" );
        
        long index = getIndexOfPage( page, pagesPerIndex);

        long indexes = 0;
        
        if( page > 0) {
			indexes = getIndexOfPage( pages, pagesPerIndex);
        }
        
		rtnStr.append( showMoveFirstPage( request, page)).append("&nbsp;");
		rtnStr.append( showMoveBeforeIndex( request, index, pagesPerIndex)).append("&nbsp;");
		rtnStr.append( showMoveBeforePage( request, page)).append("&nbsp;");

		rtnStr.append("<INPUT type=\"text\" class=\"txt w74\" value=\"").append( page)
				.append( "\" style=\"text-align: right;\" onKeyDown=\"showPageByEnter(this.value)\">").append("\n");
        rtnStr.append(" / ").append( pages).append( PAGE_UNIT_EXP).append("\n");
        
        rtnStr.append( "&nbsp;");
        rtnStr.append( showMoveNextPage( request, page, pages)).append("&nbsp;");
        rtnStr.append( showMoveNextIndex( request, index, pagesPerIndex, indexes)).append("&nbsp;");
        rtnStr.append( showMoveEndPage( request, page, pages));

        return rtnStr.append( "</span>" ).toString();
	}
    
    /**
     * 이전 인덱스로 이동하기 위한 링크 문자열을 표시하는 메서드이다.
     * <br>
     * 이전 인덱스로 이동을 표시하는 이미지를 변경하기 위해서는 설정 파일에서 move-before-index 항목의 값을 수정하라.
     * 만약, 이 항목에 값이 설정되어 있지 않다면 "[이전 인덱스]" 값이 기본으로 표시된다. 
     * <br>
     * 리턴되는 문자열에 대한 스타일을 조작하기 위해서는 CSS 파일에 page_move_before_index 클래스를 편집해야 한다.
     * 
     * @return 이전 인덱스로 이동하기 위한 링크 문자열.
     * @see laf.application.page.LPageNavigationIF#showMoveBeforeIndex()
     */
    public static String showMoveBeforeIndex( HttpServletRequest request, long index, int pagesPerIndex) {
        long targetIndex = index - 1;
        StringBuffer rtnStr =  new StringBuffer( );
        if ( targetIndex > 0 ) {
        	long targetPage = getTargetPage( targetIndex, pagesPerIndex );
        	rtnStr.append("<a href='javascript:showPage(" + targetPage + ")' onfocus=\"this.blur()\">이전10개</a>").append("\n");
        }  else {
        	rtnStr.append("<span class=\"disabled\">이전10개</span>").append("\n");
        }
        return rtnStr.toString();
               
    }
    
    /**
     * 다음 인덱스로 이동하기 위한 링크 문자열을 표시하는 메서드이다.
     * <br>
     * 다음 인덱스로 이동을 표시하는 이미지를 변경하기 위해서는 설정 파일에서 move-next-image 항목의 값을 수정하라.
     * 만약, 이 항목에 값이 설정되어 있지 않다면 "[다음 인덱스]" 값이 기본으로 표시된다. 
     * <br> 
     * 리턴되는 문자열에 대한 스타일을 조작하기 위해서는 CSS 파일에 page_move_next_index 클래스를 편집해야 한다.
     * 
     * @return 다음 인덱스로 이동하기 위한 링크 문자열.
     * @see laf.application.page.LPageNavigationIF#showMoveNextIndex()
     */
    public static String showMoveNextIndex( HttpServletRequest request, long index, int pagesPerIndex, long indexes) {
        long targetIndex = index + 1;
        StringBuffer rtnStr =  new StringBuffer( );
        if ( targetIndex <= indexes ) {
        	long targetPage = getTargetPage( targetIndex, pagesPerIndex );
        	rtnStr.append("<a href='javascript:showPage(" + targetPage + ")' onfocus=\"this.blur()\">다음10개</a>").append("\n");
        } else {
        	rtnStr.append("<span class=\"disabled\">다음10개</span>").append("\n");
        }
        return rtnStr.toString();        
    }
    
    /**
     * 이전 페이지로 이동하기 위한 링크 문자열을 표시하는 메서드이다.
     * <br>
     * 이전 페이지로 이동을 표시하는 이미지를 변경하기 위해서는 설정 파일에서 move-before-page 항목의 값을 수정하라.
     * 만약, 이 항목에 값이 설정되어 있지 않다면 "[이전 페이지]" 값이 기본으로 표시된다. 
     * <br>
     * 리턴되는 문자열에 대한 스타일을 조작하기 위해서는 CSS 파일에 page_move_before_page 클래스를 편집해야 한다.
     * 
     * @return 이전 페이지로 이동하기 위한 링크 문자열.
     * @see laf.application.page.LPageNavigationIF#showMoveBeforePage()
     */
    public static String showMoveBeforePage( HttpServletRequest request, long page) {
        StringBuffer rtnStr = new StringBuffer( "<span class=\"page_move_before_page\">" );
        long targetPage = page - 1;
        if ( targetPage > 0 ) {
            rtnStr.append( getPagingTag( request, targetPage, "이전 " + PAGE_UNIT_EXP + "로 이동", "move-before-page", "[◀]" ) );
        }
        return rtnStr.append( "</span>" ).toString();
    }
    
    /**
     * 다음 페이지로 이동하기 위한 링크 문자열을 표시하는 메서드이다.
     * <br>
     * 다음 페이지로 이동을 표시하는 이미지를 변경하기 위해서는 설정 파일에서 move-next-page 항목의 값을 수정하라.
     * 만약, 이 항목에 값이 설정되어 있지 않다면 "[다음 페이지]" 값이 기본으로 표시된다. 
     * <br> 
     * 리턴되는 문자열에 대한 스타일을 조작하기 위해서는 CSS 파일에 page_move_next_page 클래스를 편집해야 한다.
     * 
     * @return 다음 페이지로 이동하기 위한 링크 문자열.
     * @see laf.application.page.LPageNavigationIF#showMoveNextPage()
     */
    public static String showMoveNextPage( HttpServletRequest request, long page, long pages) {
        StringBuffer rtnStr = new StringBuffer( "<span class=\"page_move_next_page\">" );
        long targetPage = page + 1;
        if ( targetPage <= pages ) {
            rtnStr.append( getPagingTag( request, targetPage, "다음 " + PAGE_UNIT_EXP + "로 이동", "move-next-page", "[▶]" ) );
        }
        return rtnStr.append( "</span>" ).toString();
    }
    
    /**
     * 첫 페이지로 이동하기 위한 링크 문자열을 표시하는 메서드이다.
     * <br>
     * 첫 페이지로 이동을 표시하는 이미지를 변경하기 위해서는 설정 파일에서 move-first-page 항목의 값을 수정하라.
     * 만약, 이 항목에 값이 설정되어 있지 않다면 "[첫 페이지]" 값이 기본으로 표시된다. 
     * <br> 
     * 리턴되는 문자열에 대한 스타일을 조작하기 위해서는 CSS 파일에 page_move_first_page 클래스를 편집해야 한다.
     *  
     * @return 첫 페이지로 이동하기 위한 링크 문자열.
     * @see laf.application.page.LPageNavigationIF#showMoveFirstPage()
     */
    public static String showMoveFirstPage( HttpServletRequest request, long page) {
        StringBuffer rtnStr =  new StringBuffer( );
        if ( page > 1 ) {
            rtnStr.append( getPagingTag( request, page, "처음 " + PAGE_UNIT_EXP + "로 이동", "move-first-page", "[처음]" ) );
        }        
        return rtnStr.toString();
    }
    
    /**
     * 끝 페이지로 이동하기 위한 링크 문자열을 표시하는 메서드이다.
     * <br>
     * 끝 페이지로 이동을 표시하는 이미지를 변경하기 위해서는 설정 파일에서 move-end-page 항목의 값을 수정하라.
     * 만약, 이 항목에 값이 설정되어 있지 않다면 "[끝 페이지]" 값이 기본으로 표시된다. 
     * <br>
     * 리턴되는 문자열에 대한 스타일을 조작하기 위해서는 CSS 파일에 page_move_end_page 클래스를 편집해야 한다.
     * 
     * @return 끝 페이지로 이동하기 위한 링크 문자열.
     * @see laf.application.page.LPageNavigationIF#showMoveEndPage()
     */
    public static String showMoveEndPage( HttpServletRequest request, long page, long pages) {
        StringBuffer rtnStr = new StringBuffer( "<span class=\"page_move_end_page\">" );
        long targetPage = pages;
        if ( page < targetPage ) {
            rtnStr.append( getPagingTag( request, targetPage, "끝 " + PAGE_UNIT_EXP + "로 이동", "move-end-page", "[끝]" ) );
        }
        return rtnStr.append( "</span>" ).toString();
    }
	
    /**
     * 페이지 당 표시할 row 수를 선택할 수 있는 select 구성.
     * 
     * @param rowsPerPage row 수 기본값.
     * @return select tag 문자열.
     */
	public static String generateRowsPerPageSelector( int rowsPerPage) {
        StringBuffer rtnStr = new StringBuffer( "<span class=\"rows_per_page_select\">" );
        
        rtnStr.append( "<select class=\"" + SELECTOR_CLASS + "\" OnChange=\"changeRows(this.value)\">" );
        for ( int rowsVal = 0; rowsVal < ROWS_PER_PAGE_VALUES.length; rowsVal++ ) {
            rtnStr
                .append( "<option value=\"" )
                .append( ROWS_PER_PAGE_VALUES[rowsVal] )
                .append( "\"" );
            if ( ROWS_PER_PAGE_VALUES[rowsVal].equals( rowsPerPage+"") ) {
                rtnStr.append( " selected" );
            }
            rtnStr.append( ">").append( ROWS_PER_PAGE_VALUES[rowsVal]).append( "</option>" );
        }
        rtnStr.append( "</select> 건씩" );            

        return rtnStr.append( "</span>" ).toString();
	}
	
    /**
     * Index 당 표시할 페이지 분량을 선택할 수 있는 select 구성.
     * 
     * @param pagesPerIndex 페이지 분량 기본값.
     * @return select tag 문자열.
     */
	public static String generatePagesPerIndexSelector( int pagesPerIndex) {
        StringBuffer rtnStr = new StringBuffer( "<span class=\"pages_per_index_select\">" );
        
        rtnStr.append( "<select class=\"" + SELECTOR_CLASS + "\" OnChange=\"changePages(this.value)\">" );
        for ( int pagesVal = 0; pagesVal < PAGES_PER_INDEX_VALUES.length; pagesVal++ ) {
            rtnStr
                .append( "<option value=\"" )
                .append( PAGES_PER_INDEX_VALUES[pagesVal] )
                .append( "\"" );
            if ( PAGES_PER_INDEX_VALUES[pagesVal].equals( pagesPerIndex+"") ) {
                rtnStr.append( " selected" );
            }
            rtnStr.append( ">").append( PAGES_PER_INDEX_VALUES[pagesVal]).append( "</option>" );
        }
        rtnStr.append( "</select> ").append( PAGE_UNIT_EXP).append( "씩");            

        return rtnStr.append( "</span>" ).toString();
	}

    /**
     * 정렬 기능을 제공하는 필드를 구성하기 위한 메서드이다.
     * <br>
     * 리턴되는 문자열에 대한 스타일을 조작하기 위해서는 CSS 파일에 page_sort_field 클래스를 편집해야 한다.
     * 
     * @param orderByFieldTitle 정렬 링크가 걸려 있는 필드의 타이틀 문자열
     * @param orderByColumnName 정렬을 원하는 컬럼의 이름
     * @return 정렬 링크가 포함된 문자열
     * @see laf.application.page.LPageNavigationIF#showSortField(java.lang.String, java.lang.String)
     */
    public static String showSortField( HttpServletRequest request, String orderByFieldTitle, String orderByColumnName, String orderBy ) {
        StringBuffer rtnStr = new StringBuffer( "<span class=\"sort_field\"" );
        
        if ( ( "ORDER BY " + orderByColumnName + " DESC" ).equals( orderBy ) ) {
            rtnStr
                .append( " onclick=\"javascript:showOrderByPage(1,'ORDER BY " )
                .append( orderByColumnName )
                .append( " ASC')\" title=\"오름차순으로 정렬\">" )
                .append( orderByFieldTitle )
                .append( getImageTag( request, "order-by-desc", "오름차순으로 정렬", "▼&nbsp;" ) );
        } else if ( ( "ORDER BY " + orderByColumnName + " ASC" ).equals( orderBy ) ) {
            rtnStr
                .append( " onclick=\"javascript:showOrderByPage(1,'ORDER BY " )
                .append( orderByColumnName )
                .append( " DESC')\" title=\"내림차순으로 정렬\">" )
                .append( orderByFieldTitle )
                .append( getImageTag( request, "order-by-asc", "내림차순으로 정렬", "▲&nbsp;" ) );
        } else {
            rtnStr
            .append( " onclick=\"javascript:showOrderByPage(1,'ORDER BY " )
            .append( orderByColumnName )
            .append( " DESC')\" title=\"내림차순으로 정렬\">" )
            .append( orderByFieldTitle );        	
        }
    
        return rtnStr.append( "</span>" ).toString();
    }
    
    public static void adjustPage( Map input, Map output) {
        if ( input.get( PGI_PAGE) != null) {
	        long page = Long.parseLong( String.valueOf( input.get( PGI_PAGE)));
	        int rowsPerPage = Integer.parseInt( String.valueOf( input.get( PGI_ROWS_PER_PAGE)));
	        long count = Long.parseLong( String.valueOf( output.get( "count")));
	        long totalPage = PageUtils.getPageOfRow( count, rowsPerPage);
	        if ( page > totalPage) {
	        	if( totalPage < 1) totalPage = 1;
	        	input.put( PGI_PAGE, String.valueOf( totalPage));
	        }
        }    	
    }

    /**
     * 설정 파일에서 이미지 파일의 경로를 가져와 IMG 태그로 만들어준다.
     * 
     * @param whichImage 가져올 이미지.
     * @param altAttr IMG 태그의 ALT 속성에 넣을 문자열.
     * @param defaultImage 설정 파일에 값이 없는 경우 사용할 이미지.
     * @return IMG 태그 문자열. 설정 파일에 값이 없는 경우에는 defaultImage.
     */
    private static String getImageTag(HttpServletRequest request, String whichImage, String altAttr, String defaultImage) {
        String imagePath = request.getContextPath() + Config.getString( "doit.common.paging."+ whichImage);
        
        if ( SharedMethods.boundStringNull( imagePath) ) {
            return defaultImage;
        }
        
        return
            new StringBuffer( "<img src=\"" )
                .append( imagePath )
                .append( "\" alt=\"" )
                .append( altAttr )
                .append( "\" border=\"0\" />" )
                .toString();
    }

}
